package sk.uniba.fmph.asdf.gui.frames;

import com.alee.extended.filechooser.SelectionMode;
import com.alee.extended.filechooser.WebFileChooser;
import com.alee.laf.GlobalConstants;
import com.alee.laf.StyleConstants;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
import sk.uniba.fmph.asdf.Session;
import sk.uniba.fmph.asdf.exceptions.TemplateException;
import sk.uniba.fmph.asdf.exceptions.TemplateNotInitialized;
import sk.uniba.fmph.asdf.gui.views.MainView;
import sk.uniba.fmph.asdf.tempt.PrimaryTestFieldDef;
import sk.uniba.fmph.asdf.tempt.TemplateBuilder;
import sk.uniba.fmph.asdf.tempt.TestTemplate;
import sk.uniba.fmph.asdf.test.RelativePoint;
import sk.uniba.fmph.asdf.utils.Convertor;

/**
 * View na vytváranie a editovanie šablón testov.
 *
 * @author Jakub Gaľ
 */
public class TemplateEditorFrame extends Frame implements ActionListener {

	private static final long serialVersionUID = 1381421644685811665L;
	private final String fontFamily = "Verdana";
	private ArrayList<BufferedImage> templateImagesOrig = new ArrayList<>();
	private ArrayList<Image> templateImages = new ArrayList<>();
	private Point draggedPoint = null;
	private Rectangle draggedFieldRect = null;
	private Rectangle dragRect;
	private Point diffVector;
	private boolean drawingField;
	private boolean draggingField;
	// komponenty viewu
	private javax.swing.JButton buttonEditPoints;
	private javax.swing.JButton buttonDeleteField;
	private javax.swing.JButton buttonNewTemplate;
	private javax.swing.JButton buttonSaveTemplate;
	private javax.swing.JButton buttonLoadTemplate;
	private javax.swing.JPanel panelCenter;
	private javax.swing.JPanel panelLeft;
	private javax.swing.JPanel panelRight;
	private javax.swing.JPanel panelTemplatePreview;
	private javax.swing.JScrollPane scrollPaneTemplatePreview;
	private javax.swing.JScrollPane scrollPaneTemplates;
	private javax.swing.JTree treeTemplates;
	private javax.swing.JLabel labelFieldNumber;
	private javax.swing.JLabel labelFieldNumberValue;
	private javax.swing.JLabel labelFieldPoints;
	private javax.swing.JLabel labelFieldPointsValue;
	WebFileChooser fileChooser;

	/**
	 * Vytvorenie viewu a inicializacia jeho komponentov
	 */
	public TemplateEditorFrame(MainView parent) {
		super(parent);

		initComponents();
	}

	@Override
	public void onShow() {
//		parent.setSubtitle("Editor šablón");
	}

	/**
	 * Inicializacia komponentov
	 */
	private void initComponents() {
		setMinimumSize(new java.awt.Dimension(800, 600));
		setPreferredSize(new java.awt.Dimension(800, 600));
		setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.LINE_AXIS));

		panelLeft = new javax.swing.JPanel();
		scrollPaneTemplates = new javax.swing.JScrollPane();
		treeTemplates = new javax.swing.JTree();
		panelCenter = new javax.swing.JPanel();
		scrollPaneTemplatePreview = new javax.swing.JScrollPane(
						ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
						ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		panelTemplatePreview = new javax.swing.JPanel() {
			private static final long serialVersionUID = 5189871237059570255L;

			@Override
			public void paint(Graphics g) {
				super.paint(g);

				drawTemplatePreview(g);
			}
		};
		panelTemplatePreview.setBackground(Color.white);
		panelRight = new javax.swing.JPanel();
		buttonEditPoints = new javax.swing.JButton();
		buttonDeleteField = new javax.swing.JButton();
		buttonNewTemplate = new javax.swing.JButton();
		buttonSaveTemplate = new javax.swing.JButton();
		buttonLoadTemplate = new javax.swing.JButton();
		labelFieldNumber = new javax.swing.JLabel();
		labelFieldNumberValue = new javax.swing.JLabel();
		labelFieldPoints = new javax.swing.JLabel();
		labelFieldPointsValue = new javax.swing.JLabel();

		panelLeft.setPreferredSize(new java.awt.Dimension(175, 600));
		panelLeft.setMaximumSize(new java.awt.Dimension(175, Integer.MAX_VALUE));
		panelLeft.setLayout(new javax.swing.BoxLayout(panelLeft, javax.swing.BoxLayout.PAGE_AXIS));

		generateTemplateTree();
		scrollPaneTemplates.setViewportView(treeTemplates);

		panelLeft.add(scrollPaneTemplates);

		add(panelLeft);

		panelCenter.setBorder(javax.swing.BorderFactory.createEtchedBorder());
		panelCenter.setPreferredSize(new java.awt.Dimension(450, 600));
		panelCenter.setLayout(new java.awt.BorderLayout());

		scrollPaneTemplatePreview.setViewportView(panelTemplatePreview);

		panelCenter.add(scrollPaneTemplatePreview, BorderLayout.CENTER);

		add(panelCenter);

		panelRight.setMaximumSize(new java.awt.Dimension(175, Integer.MAX_VALUE));
		panelRight.setPreferredSize(new java.awt.Dimension(175, 600));
		panelRight.setLayout(new java.awt.GridLayout(0, 1));

		buttonNewTemplate.setText("Nová šablóna");
		buttonNewTemplate.addActionListener(this);
		panelRight.add(buttonNewTemplate);

		buttonLoadTemplate.setText("Nahrať šablónu");
		buttonLoadTemplate.addActionListener(this);
		panelRight.add(buttonLoadTemplate);

		buttonEditPoints.setText("Upraviť body");
		buttonEditPoints.addActionListener(this);
		panelRight.add(buttonEditPoints);

		buttonDeleteField.setText("Zmazať oblasť");
		buttonDeleteField.addActionListener(this);
		panelRight.add(buttonDeleteField);

		buttonSaveTemplate.setText("Uložiť šablónu");
		buttonSaveTemplate.addActionListener(this);
		panelRight.add(buttonSaveTemplate);

		labelFieldNumber.setFont(new Font(fontFamily, Font.PLAIN, 18));
		labelFieldNumber.setVerticalAlignment(SwingConstants.BOTTOM);
		labelFieldNumber.setHorizontalAlignment(SwingConstants.CENTER);
		labelFieldNumber.setText("Počet oblastí");
		panelRight.add(labelFieldNumber);

		labelFieldNumberValue.setFont(new Font(fontFamily, Font.PLAIN, 30));
		labelFieldNumberValue.setHorizontalAlignment(SwingConstants.CENTER);
		labelFieldNumberValue.setText("0");
		panelRight.add(labelFieldNumberValue);

		labelFieldPoints.setFont(new Font(fontFamily, Font.PLAIN, 18));
		labelFieldPoints.setVerticalAlignment(SwingConstants.BOTTOM);
		labelFieldPoints.setHorizontalAlignment(SwingConstants.CENTER);
		labelFieldPoints.setText("Počet bodov");
		panelRight.add(labelFieldPoints);

		labelFieldPointsValue.setFont(new Font(fontFamily, Font.PLAIN, 30));
		labelFieldPointsValue.setHorizontalAlignment(SwingConstants.CENTER);
		labelFieldPointsValue.setText("0");
		panelRight.add(labelFieldPointsValue);

		add(panelRight);

		panelTemplatePreview.addMouseListener(new MouseListener() {
			@Override
			public void mouseClicked(MouseEvent me) {
			}

			@Override
			public void mousePressed(MouseEvent me) {
				selectField(me.getPoint());

				initializeDrag(me.getPoint());
				initializeFieldDrawing();
				initializeFieldMoving();
			}

			@Override
			public void mouseReleased(MouseEvent me) {
				if (drawingField) {
					finalizeFieldDrawing();
				} else if (draggingField) {
					finalizeFieldMoving();
				}
			}

			@Override
			public void mouseEntered(MouseEvent me) {
			}

			@Override
			public void mouseExited(MouseEvent me) {
			}
		});

		panelTemplatePreview.addMouseMotionListener(new MouseMotionListener() {
			@Override
			public void mouseDragged(MouseEvent me) {
				updateDrag(me.getPoint());

				if (draggingField) {
					updateFieldMoving();
				}

				if (drawingField || draggingField) {
					repaint();
				}
			}

			@Override
			public void mouseMoved(MouseEvent me) {
			}
		});

		addComponentListener(new ComponentListener() {
			@Override
			public void componentResized(ComponentEvent ce) {
				resizeTemplateImages();
			}

			@Override
			public void componentMoved(ComponentEvent ce) {
			}

			@Override
			public void componentShown(ComponentEvent ce) {
			}

			@Override
			public void componentHidden(ComponentEvent ce) {
			}
		});

		panelTemplatePreview.addKeyListener(new KeyListener() {
			@Override
			public void keyTyped(KeyEvent ke) {
			}

			@Override
			public void keyPressed(KeyEvent ke) {
				if (ke.getKeyCode() == KeyEvent.VK_DELETE) {
					deleteField();
				} else if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
					editMaxPoints();
				}
			}

			@Override
			public void keyReleased(KeyEvent ke) {
			}
		});

	}

	/**
	 * Spracovanie kliknuti na tlacitka
	 *
	 * @param evt
	 */
	@Override
	public void actionPerformed(java.awt.event.ActionEvent evt) {
		if (evt.getSource() == buttonNewTemplate) {
			initializeTemplate();
		} else if (evt.getSource() == buttonEditPoints) {
			editMaxPoints();
		} else if (evt.getSource() == buttonDeleteField) {
			deleteField();
		} else if (evt.getSource() == buttonSaveTemplate) {
			saveTemplate();
		} else if (evt.getSource() == buttonLoadTemplate) {
			loadTemplate();
		}
	}

	/**
	 * Generovanie stromu sablon.
	 */
	private void generateTemplateTree() {
		javax.swing.tree.DefaultMutableTreeNode treeNodeRoot = new javax.swing.tree.DefaultMutableTreeNode("Šablóny");

		java.util.HashSet<TestTemplate> templates;
		templates = Session.getAllTemplates();
		for (TestTemplate t : templates) {
			javax.swing.tree.DefaultMutableTreeNode treeNodeTemplate = new javax.swing.tree.DefaultMutableTreeNode(t.toString());
			treeNodeRoot.add(treeNodeTemplate);
		}

		treeTemplates.setModel(new javax.swing.tree.DefaultTreeModel(treeNodeRoot));
		treeTemplates.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

	}

	/**
	 * Inicializacia prazdnej sablony.
	 */
	private void initializeTemplate() {
		if (chooseBackgroundImages()) {
			TemplateBuilder.initializeTemplate();
		}
	}

	/**
	 * Vyber a nacitanie obrazkovych suborov ktore budu sluzit ako podklad
	 * sablony. Otvori FileChooser dialog a po zvoleni obrazkovych suborov ich
	 * ulozi do lokalnej stavovej premennej a vytvori naskalovane kopie, ktore sa
	 * budu zobrazovat.
	 *
	 * @return
	 */
	private boolean chooseBackgroundImages() {
		if (fileChooser == null) {
			fileChooser = new WebFileChooser(parent, "Vyberte predlohu testu");
			fileChooser.setCurrentDirectory(System.getProperty("user.home"));
			fileChooser.setSelectionMode(SelectionMode.MULTIPLE_SELECTION);
			fileChooser.setAvailableFilter(GlobalConstants.IMAGES_FILTER);
			fileChooser.setChooseFilter(GlobalConstants.IMAGES_FILTER);

		}
		fileChooser.setVisible(true);
		if (fileChooser.getResult() == StyleConstants.OK_OPTION) {
			final List<File> imageFiles = fileChooser.getSelectedFiles();

			if (imageFiles.isEmpty()) {
				JOptionPane.showMessageDialog(parent, "Musíte zvoliť aspoň jeden obrázok", "Chyba!", JOptionPane.ERROR_MESSAGE);
			} else {
				templateImages.clear();
				templateImagesOrig.clear();
				scrollPaneTemplatePreview.repaint();

                Session.addStatusMessage("Škálujem obrázky...");
//                parent.setStatusLabel("Škálujem obrázky...", MainView.WAIT_ICON);

				new Thread(new Runnable() {

                    @Override
                    public void run() {
                        for (File f : imageFiles) {
                            try {
                                Image img = ImageIO.read(f);
                                int width = img.getWidth(null);
                                int height = img.getHeight(null);
                                if (width > 1500) {
                                    double ratio = (float) 1500 / width;
                                    width = 1500;
                                    height = (int) Math.round(height * ratio);
                                }

                                BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                                Graphics2D g = bimg.createGraphics();
                                g.drawImage(img.getScaledInstance(width, height, Image.SCALE_SMOOTH), null, null);

                                templateImagesOrig.add(bimg);

                                templateImages.add(null);
                            } catch (IOException ex) {
                                Logger.getLogger(TemplateEditorFrame.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }

                        resizeTemplateImages();
                    }


                }).start();
                parent.clearStatusLabel();
				return true;
			}
		}
		return false;
	}

	/**
	 * Vytvorenie sablony z uz existujucej. Nacita podkladove obrazky a pouzije
	 * sablonu zvolenu v zozname ako novu sablonu.
	 */
	private void loadTemplate() {
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) treeTemplates.getLastSelectedPathComponent();
		if (node != null && !node.isRoot() && (node.getUserObject() instanceof String)) {
			String filename = (String) node.getUserObject();

			try {
				if (chooseBackgroundImages()) {
					TemplateBuilder.initializeTemplate(filename);
				}
			} catch (TemplateException ex) {
				JOptionPane.showMessageDialog(parent, "Pri načítavaní šablóny došlo k chybe", "Chyba!", JOptionPane.ERROR_MESSAGE);
			} catch (IOException ex) {
				JOptionPane.showMessageDialog(parent, "Súbor šablóny sa nepodarilo načítať", "Chyba!", JOptionPane.ERROR_MESSAGE);
			}
		} else {
			JOptionPane.showMessageDialog(parent, "Najprv musíte zvoliť šablónu, ktorú chcete nahrať, zo zoznamu šablón", "Zvoľte šablónu", JOptionPane.INFORMATION_MESSAGE);
		}
	}

    /**
	 * Vytvori kopie originalnych podkladovych obrazkov a naskaluje ich podla
	 * velkosti okna.
	 */
	synchronized private void resizeTemplateImages() {
		int height = 0;
		int width = scrollPaneTemplatePreview.getWidth() - scrollPaneTemplatePreview.getVerticalScrollBar().getWidth();

		for (int i = 0; i < templateImagesOrig.size(); i++) {
			Image im = templateImagesOrig.get(i).getScaledInstance(width, -1, Image.SCALE_SMOOTH);
			templateImages.set(i, im);

			height += im.getHeight(null);
		}

		panelTemplatePreview.setPreferredSize(new java.awt.Dimension(width, height));
		int scrollAmount = Math.round(height / scrollPaneTemplatePreview.getHeight() * 20);
		scrollPaneTemplatePreview.getVerticalScrollBar().setUnitIncrement(scrollAmount);

		panelTemplatePreview.revalidate();
		panelTemplatePreview.repaint();
	}

	/**
	 * Vykresli podkladove obrazky a sablonove oblasti s poctami bodov.
	 *
	 * @param g - graficka plocha do ktorej sa ma kreslit
	 */
	private void drawTemplatePreview(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setStroke(new BasicStroke(2));
		Font font = new Font(fontFamily, Font.BOLD, 24);
		g2.setFont(font);
		FontRenderContext frc = new FontRenderContext(null, true, false);

		if (TemplateBuilder.initialized()) {
			int ty = 0;
			for (Image i : templateImages) {
				g2.drawImage(i, 0, ty, null);
				ty += i.getHeight(null);
			}

			PrimaryTestFieldDef selField = TemplateBuilder.getSelectedField();

			for (PrimaryTestFieldDef f : TemplateBuilder.getFields()) {
				if (f != selField) {
					RelativePoint tl = f.getTopLeft();
					RelativePoint br = f.getBottomRight();
					Dimension d = panelTemplatePreview.getSize();

					Point p1 = Convertor.relToAbs(tl, d);
					Point p2 = Convertor.relToAbs(br, d);
					int w = p2.x - p1.x;
					int h = p2.y - p1.y;

					g2.setColor(new Color(0, 255, 0, 50));
					g2.fillRect(p1.x, p1.y, w, h);
					g2.setColor(Color.green);
					g2.drawRect(p1.x, p1.y, w, h);
					g2.setColor(Color.black);

					String points = String.valueOf(f.getMaxPoints());
					Rectangle2D bounds = font.getStringBounds(points, frc);

					float textX = p1.x + (w / 2 - (float) bounds.getCenterX());
					float textY = p1.y + (h / 2 - (float) bounds.getCenterY());

					g2.drawString(points, textX, textY);
				}
			}

			if (selField != null) {
				int x, y, w, h;

				if (draggingField) {
					x = draggedFieldRect.x;
					y = draggedFieldRect.y;
					w = draggedFieldRect.width;
					h = draggedFieldRect.height;
				} else {
					RelativePoint tl = selField.getTopLeft();
					RelativePoint br = selField.getBottomRight();
					Dimension d = panelTemplatePreview.getSize();

					Point p1 = Convertor.relToAbs(tl, d);
					Point p2 = Convertor.relToAbs(br, d);
					x = p1.x;
					y = p1.y;
					w = p2.x - p1.x;
					h = p2.y - p1.y;
				}

				g2.setColor(new Color(0, 0, 255, 50));
				g2.fillRect(x, y, w, h);
				g2.setColor(Color.blue);
				g2.drawRect(x, y, w, h);
				g2.setColor(Color.black);

				String points = String.valueOf(selField.getMaxPoints());
				Rectangle2D bounds = font.getStringBounds(points, frc);

				float textX = x + (w / 2 - (float) bounds.getCenterX());
				float textY = y + (h / 2 - (float) bounds.getCenterY());

				g2.drawString(points, textX, textY);
			}

			if (drawingField) {
				int x = dragRect.width > 0 ? dragRect.x : dragRect.x + dragRect.width;
				int y = dragRect.height > 0 ? dragRect.y : dragRect.y + dragRect.height;
				int width = Math.abs(dragRect.width);
				int height = Math.abs(dragRect.height);

				g2.setColor(new Color(255, 0, 0, 50));
				g2.fillRect(x, y, width, height);
				g2.setColor(Color.red);
				g2.drawRect(x, y, width, height);
				g2.setColor(Color.black);
			}
		}
	}

	/**
	 * Ulozi editovanu sablonu so zadanym nazvom. Otvori input dialog a nacita
	 * nazov sablony od pouzivatela, ktory nasledne posle do TemplateBuildera,
	 * ktory sablonu ulozi. Nasledne sa vykona synchronizacia a znova sa
	 * vygeneruje zoznam sablon.
	 */
	private void saveTemplate() {
		if (TemplateBuilder.initialized()) {
			if (TemplateBuilder.getTotalFields() == 0) {
				JOptionPane.showMessageDialog(parent, "Musíte pridať aspoň jednu oblasť", "Chyba!", JOptionPane.ERROR_MESSAGE);
			} else {
				String title = JOptionPane.showInputDialog(super.parent, "Zadaj názov šablóny: ");

				if (title != null) {
					if (title.equals("")) {
						JOptionPane.showMessageDialog(parent, "Názov šablóny je povinný", "Chyba!", JOptionPane.ERROR_MESSAGE);
					} else {
						try {
							TestTemplate template = TemplateBuilder.finalizeTemplate(title, Session.getAccount());
							templateImages.clear();
							templateImagesOrig.clear();
							panelTemplatePreview.repaint();
							panelTemplatePreview.setSize(scrollPaneTemplatePreview.getPreferredSize());
							scrollPaneTemplatePreview.revalidate();
							
							labelFieldNumberValue.setText(String.valueOf(TemplateBuilder.getTotalFields()));
							labelFieldPointsValue.setText(String.valueOf(TemplateBuilder.getTotalPoints()));

							Session.addTemplate(template);
							generateTemplateTree();
							JOptionPane.showMessageDialog(parent, "Šablóna bola uložená", "Oznam", JOptionPane.INFORMATION_MESSAGE);
						} catch (TemplateNotInitialized ex) {
							JOptionPane.showMessageDialog(parent, "Žiadna šablóna nie je načítaná v editore", "Chyba!", JOptionPane.ERROR_MESSAGE);
						} catch (IOException ex) {
							JOptionPane.showMessageDialog(parent, "Súbor šablóny sa nepodarilo uložiť", "Chyba!", JOptionPane.ERROR_MESSAGE);
						}
					}
				}
			}
		}
		else {
			JOptionPane.showMessageDialog(parent, "V editore nie je otvorená žiadna šablóna", "Chyba!", JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Nastavi oblast, v ktorej sa nachadza vstupny bod ako aktualne zvolenu. Ak
	 * sa bod nenachadza v ziadnej oblasti, nastavi sa aktualne zvolena oblast na
	 * null.
	 *
	 * @param p - bod
	 */
	private void selectField(Point p) {
		Dimension d = panelTemplatePreview.getSize();
		RelativePoint rp = Convertor.absToRel(p, d);
		TemplateBuilder.selectField(rp);
		panelTemplatePreview.requestFocusInWindow();
		panelTemplatePreview.repaint();
	}

	/**
	 * Prida novu oblast do sablony. Ak sa nova oblast prekryva s existujucou,
	 * oblast pridana nebude. Inak bude pouzivatel vyzvany na zadanie maximalneho
	 * poctu bodov pre novu oblast a vsetky udaje sa odoslu do TemplateBuildera,
	 * ktory ich spracuje.
	 *
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 */
	private void saveField(int x, int y, int width, int height) {
		Point p1 = new Point(x, y);
		Point p2 = new Point(x + width, y + height);
		Dimension d = panelTemplatePreview.getSize();
		RelativePoint tl = Convertor.absToRel(p1, d);
		RelativePoint br = Convertor.absToRel(p2, d);

		if (TemplateBuilder.isOverlaping(tl, br)) {
			JOptionPane.showMessageDialog(panelCenter, "Nová oblasť sa prekrýva s existujúcou", "Chyba", JOptionPane.ERROR_MESSAGE);
		} else {
			int maxPoints = 0;
			boolean validNumber = false;

			while (!validNumber) {
				validNumber = true;

				String result = JOptionPane.showInputDialog(panelCenter, "Zadaj maximálny počet bodov pre danú oblasť", "Počet bodov", JOptionPane.QUESTION_MESSAGE);

				if (result == null) {
					return;
				} else {
					try {
						maxPoints = Integer.parseInt(result);
					} catch (NumberFormatException e) {
						validNumber = false;
					}

					if (maxPoints <= 0) {
						validNumber = false;
					}

					if (!validNumber) {
						JOptionPane.showMessageDialog(panelCenter, "Musíte zadať prirodzené číslo", "Chyba!", JOptionPane.ERROR_MESSAGE);
					}
				}
			}

			TemplateBuilder.addField(tl, br, maxPoints);

			labelFieldNumberValue.setText(String.valueOf(TemplateBuilder.getTotalFields()));
			labelFieldPointsValue.setText(String.valueOf(TemplateBuilder.getTotalPoints()));
		}
	}

	/**
	 * Spracovanie posunutia oblasti. Prekonvertujeme si lokalnu reprezentaciu
	 * posunutej oblasti na relativne pozicie a zavolame editacnu metodu
	 * TemplateBuildera.
	 */
	private void moveField() {
		Point tl = new Point(draggedFieldRect.x, draggedFieldRect.y);
		Point br = new Point(tl.x + draggedFieldRect.width, tl.y + draggedFieldRect.height);

		RelativePoint rtl = Convertor.absToRel(tl, panelTemplatePreview.getSize());
		RelativePoint rbr = Convertor.absToRel(br, panelTemplatePreview.getSize());

		PrimaryTestFieldDef f = TemplateBuilder.getSelectedField();
		if (TemplateBuilder.isOverlapingAfterDrag(rtl, rbr, f)) {
			JOptionPane.showMessageDialog(panelCenter, "Presunutá oblasť sa prekrýva s existujúcou", "Chyba", JOptionPane.ERROR_MESSAGE);
		} else {

			TemplateBuilder.editField(rtl, rbr, f.getMaxPoints());
		}
		draggedFieldRect = null;
		panelTemplatePreview.repaint();
	}

	private void editMaxPoints() {
		if (TemplateBuilder.getSelectedField() != null) {
			PrimaryTestFieldDef field = TemplateBuilder.getSelectedField();

			int maxPoints = 0;
			boolean validNumber = false;

			while (!validNumber) {
				validNumber = true;

				String result = JOptionPane.showInputDialog(panelCenter, "Zadaj maximálny počet bodov pre danú oblasť", "Počet bodov", JOptionPane.QUESTION_MESSAGE);

				if (result == null) {
					return;
				} else {
					try {
						maxPoints = Integer.parseInt(result);
					} catch (NumberFormatException e) {
						validNumber = false;
					}

					if (maxPoints <= 0) {
						validNumber = false;
					}

					if (!validNumber) {
						JOptionPane.showMessageDialog(panelCenter, "Musíte zadať prirodzené číslo", "Chyba!", JOptionPane.ERROR_MESSAGE);
					}
				}
			}

			TemplateBuilder.editField(field.getTopLeft(), field.getBottomRight(), maxPoints);
			labelFieldPointsValue.setText(String.valueOf(TemplateBuilder.getTotalPoints()));
			panelTemplatePreview.repaint();
		} else {
			JOptionPane.showMessageDialog(panelCenter, "Musíte zvoliť oblasť, ktorej počet bodov chcete upraviť", "Chyba!", JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Odstrani aktualne zvolenu oblast zo sablony.
	 * Ak ziadna nie je zvolena, zobrazi o tom hlasenie.
	 */
	private void deleteField() {
		if (TemplateBuilder.getSelectedField() != null) {
			TemplateBuilder.deleteField();
			labelFieldNumberValue.setText(String.valueOf(TemplateBuilder.getFields().size()));
			labelFieldPointsValue.setText(String.valueOf(TemplateBuilder.getTotalPoints()));
			panelTemplatePreview.repaint();
		} else {
			JOptionPane.showMessageDialog(parent, "Musíte zvoliť oblasť na zmazanie", "Chyba!", JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * Pomocna metoda na inicializovanie obdlznika, ktory predstavuje oblast
	 * vyznacenu tahom mysi.
	 *
	 * @param p - lavy horny roh obldznika
	 */
	private void initializeDrag(Point p) {
		diffVector = new Point(0, 0);
		dragRect = new Rectangle(p.x, p.y, 0, 0);
	}

	/**
	 * Pomocna metoda na aktualizaciu rozmerov obdlznika, ktory predstavuje oblast
	 * vyznacenu tahom mysi.
	 *
	 * @param p - pravy dolny roh obdlznika
	 */
	private void updateDrag(Point p) {
		diffVector.setLocation(p.x - dragRect.x - dragRect.width, p.y - dragRect.y - dragRect.height);
		dragRect.setSize(dragRect.width + diffVector.x, dragRect.height + diffVector.y);
	}

	/**
	 * Inicializacia kreslenia oblasti. Ak mozme kreslit, zapamatame si ze
	 * kreslime.
	 */
	private void initializeFieldDrawing() {
		if (TemplateBuilder.initialized() && TemplateBuilder.getSelectedField() == null) {
			drawingField = true;
		}
	}

	/**
	 * Metoda na spracovanie nakreslenej oblasti. Skontrolujeme vyznacenu oblast,
	 * ak je lavy horny a pravy dolny roh prehodeny, vymenime ich.
	 */
	private void finalizeFieldDrawing() {
		if (TemplateBuilder.initialized()) {
			drawingField = false;

			int x = dragRect.width > 0 ? dragRect.x : dragRect.x + dragRect.width;
			int y = dragRect.height > 0 ? dragRect.y : dragRect.y + dragRect.height;
			int width = Math.abs(dragRect.width);
			int height = Math.abs(dragRect.height);

			dragRect.x = x;
			dragRect.y = y;
			dragRect.width = width;
			dragRect.height = height;

			if (width > 5 && height > 5) {
				saveField(x, y, width, height);
			}

			panelTemplatePreview.repaint();
		}
	}

	/**
	 * Inicializacia presuvania oblasti. Ak mozme presuvat, zpamatame si ze
	 * presuvame a vytvorime si lokalny obdlznik s rozmermi presuvanej oblasti.
	 */
	private void initializeFieldMoving() {
		if (TemplateBuilder.getSelectedField() != null) {
			draggingField = true;

			PrimaryTestFieldDef f = TemplateBuilder.getSelectedField();
			Point tl = Convertor.relToAbs(f.getTopLeft(), panelTemplatePreview.getSize());
			Point br = Convertor.relToAbs(f.getBottomRight(), panelTemplatePreview.getSize());

			draggedFieldRect = new Rectangle(tl.x, tl.y, br.x - tl.x, br.y - tl.y);
		}
	}

	/**
	 * Aktualizacia presuvania oblasti. Podla vektora posunutia oproti predoslej
	 * pozicii mysi posunieme nasu lokalnu reprezentaciu presuvanej oblasti a
	 * skontrolujeme ci sa este nachadza cela vnutri sablony. Ak nie tak tuto
	 * zmenu nevykoname.
	 */
	private void updateFieldMoving() {
		int x1 = draggedFieldRect.x + diffVector.x;
		int y1 = draggedFieldRect.y + diffVector.y;
		int x2 = x1 + draggedFieldRect.width;
		int y2 = y1 + draggedFieldRect.height;

		if (x1 > 0 && y1 > 0 && x2 <= panelTemplatePreview.getWidth() && y2 <= panelTemplatePreview.getHeight()) {
			draggedFieldRect.setLocation(draggedFieldRect.x + diffVector.x, draggedFieldRect.y + diffVector.y);
		}
	}

	/**
	 * Metoda na spracovanie posunutia oblasti. Skontrolujeme ci je vektor
	 * posunutia nenulovy a ak ano posunutie zapiseme.
	 */
	private void finalizeFieldMoving() {
		if (TemplateBuilder.initialized()) {
			draggingField = false;

			if (dragRect.width != 0 || dragRect.height != 0) {
				moveField();
				draggedFieldRect = null;

				panelTemplatePreview.repaint();
			}
		}
	}
}
